home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Eagles Nest BBS 8
/
Eagles_Nest_Mac_Collection_Disc_8.TOAST
/
Developer Tools⁄Additions
/
MacTCPToolBx
/
Source Code ƒ
/
TCPRecvMsg.p
< prev
next >
Wrap
Text File
|
1989-06-01
|
9KB
|
278 lines
(*
TCPRecvMsg(connectionID,waitTime,OKChar,limit) -- Return a message, where a message is
defined as either a line starting with the OKChar (if the first line does not start with this,
then the first line is returned surrounded by "•••"; this is an error indication), which should
be stripped from the message, followed by lines of text until a period on a line be itself is reached,
which final line is also stipped; or if OKChar is empty, then no initial line, but just lines of text
until a period on a line by itself, which is stripped. In addition, the following editing is performed on
the incoming text: linefeeds are removed; control-Hs and the characters immediately preceeding them
are removed; ".." at the start of lines is changed is "."; tabs are converted to spaces. If waitTime
ticks go by without reading a whole message, then return "••• time out •••". If limit characters
are input without reading a whole message, then "••• message too big •••" is appended
to the truncated message (but it's all read anyway). This routine should be able to read
SMTP, NNTP, and POP messages.
To compile and link this file using Macintosh Programmer's Workshop,
pascal -w TCPRecvMsg.p
link -m ENTRYPOINT -o HyperCommands -rt XFCN=7867 -sn Main=TCPRecvMsg ∂
TCPRecvMsg.p.o "{Libraries}HyperXLib.o" "{MPW}"Libraries:interface.o
© Copyright 1989 by Apple Computer, Inc.
Initial coding 1/89 by Harry R. Chesley.
Added empty OKChar processing 4/3/89, Harry R. Chesley.
*)
{$R-}
{$S TCPRecvMsg } { Segment name must be the same as the command name. }
unit DummyUnit;
interface
uses MemTypes, QuickDraw, OSIntf, ToolIntf, HyperXCmd;
procedure EntryPoint(paramPtr: XCmdPtr);
implementation
const
LINEFEED = 10; { ASCII for line feed. }
RETURN = 13; { ASCII for carriage return. }
CONTROLH = 8; { ASCII for backspace. }
TAB = 9; { ASCII for tab. }
FORMFEED = 12; { ASCII for form feed. }
TABSTOPS = 8; { Number of columns per tab stop. }
procedure TCPRecvMsg(paramPtr: XCmdPtr); forward;
procedure EntryPoint(paramPtr: XCmdPtr);
begin
TCPRecvMsg(paramPtr);
end;
procedure TCPRecvMsg(paramPtr: XCmdPtr);
type stateList =
(firstChar,lastErrorLinefeed,secondWord,endOfOKLine,endOfLine,firstPeriod,
secondPeriod,lastLinefeed);
var str: Str255;
l: longInt;
i: integer;
waitForChars: longInt; { Ticks to wait until for characters (compated to TickCount). }
resultHand: Handle; { A handle to the result string. }
resultSize: longInt; { The size of the result string (minus the zero termination tacked on last). }
limit: longInt; { Size limitation. }
okChar: SignedByte; { Message is OK if first char is this. }
theChar: SignedByte; { Input character. }
tabColumn: integer; { Current column. }
procedure Fail(errMsg: Str255); { set theResult and quit }
begin
paramPtr^.returnValue := PasToZero(paramPtr,errMsg);
exit(TCPRecvMsg);
end;
{$I TCPUtil.inc}
procedure disposAndFail(err: str255);
{ Fail routine used after the result handle has been allocated. }
begin
DisposHandle(resultHand);
Fail(err);
end;
procedure putByte(b: SignedByte);
{ Put the byte b after the output handle, increasing the handle's size in the process. }
var p: Ptr;
begin
if resultSize < limit then
begin
resultSize := resultSize+1;
SetHandleSize(resultHand,resultSize);
if MemError <> noErr then disposAndFail('§§§ SetHandleSize failed §§§');
p := Ptr(ord4(resultHand^)+resultSize-1);
p^ := b;
end;
end;
procedure putString(s: Str255);
{ Put each byte in the string. }
var i: integer;
begin
for i := 1 to length(s) do
putByte(SignedByte(s[i]));
end;
function nextByte: SignedByte;
{ Return the next byte in the buffer, reading more in if necessary. }
var waitUntil: longInt;
readIn: longInt;
begin
with Connection^ do
begin
if incomingSize = 0 then
begin
waitUntil := TickCount + waitForChars;
while true do
begin
{ Check the status. }
ZeroIOParms;
SyncControlBlock.csCode := TCPcsStatus;
if PBControl(@SyncControlBlock,false) <> noErr then
disposAndFail('§§§ TCP status failed §§§');
readIn := ControlWordAtOffset(60);
{ If there's something to read, do so. }
if readIn > 0 then
begin
{ Read only up to the buffer size. }
if readIn > INCOMINGBUFSIZE then readIn := INCOMINGBUFSIZE;
{ Issue the read. }
ZeroIOParms;
SyncControlBlock.csCode := TCPcsRcv;
PutControlLongAtOffset(ord4(@inBuf),36);
PutControlWordAtOffset(readIn,40);
if PBControl(@SyncControlBlock,false) <> noErr then
disposAndFail('§§§ TCP read failed §§§');
incomingSize := readIn;
incomingPtr := @inBuf;
leave;
end
{ If not, check the timeout condition. }
else if TickCount > waitUntil then
begin
putByte(0);
paramPtr^.returnValue := resultHand;
exit(TCPRecvMsg);
end;
end;
end;
{ Get the byte. }
nextByte := incomingPtr^;
incomingPtr := Ptr(ord4(incomingPtr)+1);
incomingSize := incomingSize-1;
end;
end;
begin
if paramPtr^.paramCount <> 4 then Fail('§§§ parameter count is not 4 §§§');
SetUpConnectionID;
waitForChars := GetLongParm(2); { Second parameter is whether to wait. }
GetStrParm(3,str); { Third parameter is OK char. }
if length(str) = 0 then okChar := 0
else okChar := SignedByte(str[1]);
limit := GetLongParm(4); { Fourth parameter is the size limit. }
{ Create the return handle. }
resultHand := NewHandle(0);
resultSize := 0;
{ Start in the first column. }
tabColumn := 0;
{ Get the first character. }
if okChar <> 0 then theChar := nextByte;
{ Check if this is a good message or an error. }
if (theChar <> okChar) and (okChar <> 0) then
begin
{ If error, return the line, surounded by bullets. }
putString('••• ');
while theChar <> RETURN do
begin
putByte(theChar);
theChar := nextByte;
end;
putString(' •••');
{ Skip the linefeed. }
theChar := nextByte;
end
else
begin
{ Skip the first line. }
if okChar <> 0 then repeat until nextByte = LINEFEED;
{ Repeat for each line. }
while true do
begin
{ Check the first char for period. }
theChar := nextByte;
if theChar = ord('.') then
begin
{ Initial period. Might be end-of-message. Check the second char. }
theChar := nextByte;
if theChar = RETURN then
begin
{ End-of-message. Skip the linefeed and return. }
theChar := nextByte;
leave;
end
{ Otherwise, output the initial period. }
else putByte(ord('.'));
{ Plus the next char if it wasn't a doubled initial period. }
if theChar <> ord('.') then putByte(theChar);
{ Get the next char in the line. }
theChar := nextByte;
end;
{ Do the rest of the line. }
while theChar <> LINEFEED do
begin
if theChar = TAB then
begin
{ Space out to the tab stop. }
repeat
putByte(SignedByte(' '));
tabColumn := tabColumn+1;
until (tabColumn mod TABSTOPS) = 0;
end
else if theChar = CONTROLH then
begin
{ Back up one, if there's anything to back up over. }
if (tabColumn > 0) and (resultSize > 0) then
begin
resultSize := resultSize-1;
tabColumn := tabColumn-1;
end;
end
else if theChar = FORMFEED then
begin
{ Insert a page-break. }
for i := 1 to 20 do putByte(SignedByte('◊'));
for i := 1 to 24 do putByte(RETURN);
end
else if theChar <> LINEFEED then
begin
{ Just put the character out straight, and adjust the tabbing. }
putByte(theChar);
if theChar = RETURN then tabColumn := 0
else tabColumn := tabColumn+1;
end;
theChar := nextByte;
end;
end;
{ Check if we overrun the allowed size. }
if resultSize = limit then putString('••• message too big •••');
end;
{ Add in the zero termination for the string. }
putByte(0);
{ Return the handle. }
paramPtr^.returnValue := resultHand;
end;
end.